package fisherrors

import (
	"fengxueguang/novel-assistan/core/log"
	"fmt"
	"github.com/pkg/errors"
)

type EntryCaller struct {
	Defined  bool
	PC       uintptr
	File     string
	Line     int
	Function string
}
type CheckedEntry struct {
	Message string
	Caller  EntryCaller
	Stack   string
}

type FishError struct {
	Code int         `json:"code"`    // 业务码
	Msg  string      `json:"message"` // 描述信息
	Data interface{} `json:"data"`    // 业务数据
	Err  error       `json:"err"`     // 原始错误 最好用 pkgerr 有堆栈信息

	//addCaller      bool
	//callerSkip     int
	//FullStackDepth bool
	//CheckEntry     *CheckedEntry
}

func (e *FishError) Error() string {
	errStr := ""
	if len(e.Msg) > 0 {
		errStr = e.Msg
	} else if e.Err != nil {
		errStr = e.Err.Error()
	}

	return errStr
}

func (e *FishError) ToString() string {
	return fmt.Sprintf("fish_error=%v||fish_error_code=%v||fish_error_data=%v||origin_err_msg=%+v", e.Msg, e.Code, e.Data, e.Err)
}

func (e *FishError) SetCode(code int) *FishError {
	e.Code = code
	return e
}
func (e *FishError) SetErrCode(code ErrCode) *FishError {
	e.Code = int(code)
	return e
}
func (e *FishError) SetMsg(msg string) *FishError {
	e.Msg = msg
	return e
}
func NewWithErrCode(code ErrCode) *FishError {
	return &FishError{
		Err:  errors.New(code.String()),
		Code: int(code),
	}
}

func (e *FishError) SetData(data interface{}) *FishError {
	e.Data = data
	return e
}

func NewFishErrorWithErr(err error) *FishError {
	return &FishError{
		Err: err,
	}
}

func NewFishError(msg string) *FishError {
	return &FishError{
		Msg: msg,
	}
}

func NewFishErrorWithData(msg string, data interface{}) *FishError {
	return &FishError{
		Msg:  msg,
		Data: data,
	}
}

//func GetError(e *FishError, data interface{}) *FishError {
//	return &FishError{
//		Msg:  e.Msg,
//		Code: e.Code,
//		Data: data,
//	}
//}

func GetSimpleStack(call int) string {
	const callerSkipOffset = 2
	stackDepth := stacktraceFirst
	stack := captureStacktrace(call+callerSkipOffset, stackDepth)
	defer stack.Free()

	if stack.Count() == 0 {
		log.Error("Logger.check error: failed to get caller\n")
		return ""
	}
	frame, _ := stack.Next()
	return fmt.Sprintf(" stack: %s:%d %s\n", frame.File, frame.Line, frame.Function)
}
